import { useCallback, useReducer, useState } from "react";

const UNDO = "UNDO";
const REDO = "REDO";
const SET = "SET";
const RESET = "RESET";

type ActionType = "UNDO" | "REDO" | "SET" | "RESET";

type State<T> = {
  past: T[];
  present: T;
  future: T[];
};

type Action<T> = { newPresent?: T; type: ActionType };

const undoReducer = <T>(state: State<T>, action: Action<T>) => {
  const { past, present, future } = state;
  const { newPresent, type } = action;

  switch (type) {
    case "UNDO": {
      if (past.length === 0) return state;
      const previous = past[past.length - 1];
      const newPast = past.slice(0, past.length - 1);
      return {
        past: newPast,
        present: previous,
        future: [...future, present],
      };
    }
    case "REDO": {
      if (future.length === 0) return state;
      const previous = future[0];
      const newFuture = future.slice(1);
      return {
        past: [...past, present],
        present: previous,
        future: newFuture,
      };
    }
    case "SET": {
      if (present === newPresent) return state;
      return {
        past: [...past, present],
        present: newPresent,
        future: [],
      };
    }
    case "RESET": {
      return {
        past: [],
        present: newPresent,
        future: [],
      };
    }
  }

  return state;
};

export const useUndo = <T>(initialPresent: T) => {
  //useReducer版本
  const [state, dispatch] = useReducer(undoReducer, {
    past: [],
    present: initialPresent,
    future: [],
  } as State<T>);

  // const [ past, setPast ] = useState<T[]>([])
  // const [ present, setPresent ] = useState(initialPresent)
  // const [ future, setFuture ] = useState<T[]>([])

  // const [state, setState] = useState<{
  //   past: T[];
  //   present: T;
  //   future: T[]
  // }>({
  //   past: [],
  //   present: initialPresent,
  //   future: []
  // })

  const canUndo = state.past.length !== 0;
  const canRedo = state.future.length !== 0;
  const undo = useCallback(() => dispatch({ type: "UNDO" }), []);
  const redo = useCallback(() => dispatch({ type: "REDO" }), []);
  const set = useCallback(
    (newPresent: T) => dispatch({ newPresent: newPresent, type: "SET" }),
    []
  );
  const reset = useCallback(
    (newPresent: T) => dispatch({ newPresent: newPresent, type: "RESET" }),
    []
  );
  // const undo = useCallback(() => {
  //------------------使用useCallback处理-----------------
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if(past.length === 0) return currentState
  //     const previous = past[past.length - 1]
  //     const newPast = past.slice(0, past.length - 1)
  //     return {
  //       past: newPast,
  //       present: previous,
  //       future: [...future, present]
  //     }
  //   })
  //-----------------------------------
  // if(!canUndo) return
  // const previous = past[state.past.length - 1]
  // const newPast = past.slice(0, state.past.length - 1)
  //
  // setPast(newPast)
  // setPresent(previous)
  // setFuture([...future, present])
  // }, [])
  // const redo = useCallback(() => {
  //------------------使用useCallback处理-----------------
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if(future.length === 0) return currentState
  //     const previous = future[0]
  //     const newFuture = future.slice(1)
  //     return {
  //       past: [...past, present],
  //       present: previous,
  //       future: newFuture
  //     }
  //   })
  //-----------------------------------
  // if(!canRedo) return
  // const next = future[0]
  // const newFuture = future.slice(1)
  //
  // setPast([...past, present])
  // setPresent(next)
  // setFuture(newFuture)
  // }, [])
  // const set = useCallback((newPresent: T) => {
  //------------------使用useCallback处理-----------------
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if(present=== newPresent) return currentState
  //     return {
  //       past: [...past, present],
  //       present: newPresent,
  //       future: []
  //     }
  //   })
  //-----------------------------------
  // if(present === newPresent) return
  //
  // setPast([...past, present])
  // setPresent(newPresent)
  // setFuture([])
  // }, [])

  // const reset = useCallback((newPresent: T) => {
  //------------------使用useCallback处理-----------------
  //   setState(() => {
  //     return {
  //       past: [],
  //       present: newPresent,
  //       future: []
  //     }
  //   })
  //-----------------------------------
  // setPast([])
  // setPresent(newPresent)
  // setFuture([])
  // }, [])
  return [state, { set, reset, undo, redo, canUndo, canRedo }] as const;
};
